home *** CD-ROM | disk | FTP | other *** search
/ Super PC 26 / Super PC 26 (Shareware).iso / spc / util / fractint / source / miscres.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-23  |  46.8 KB  |  1,574 lines

  1. /*
  2.     Resident odds and ends that don't fit anywhere else.
  3. */
  4.  
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include <malloc.h>
  11. #ifndef XFRACT
  12. #include <stdarg.h>
  13. #include <io.h>
  14. #include <dos.h>
  15. #else
  16. #include <varargs.h>
  17. #endif
  18. #include <math.h>
  19. /*#ifdef __TURBOC__
  20. #include <dir.h>
  21. #endif  */
  22.  
  23. #include "fractint.h"
  24. #include "fractype.h"
  25. #include "helpdefs.h"
  26. #include "prototyp.h"
  27.  
  28. /* routines in this module    */
  29.  
  30. static    void trigdetails(char *);
  31. static void area(void);
  32. static int find_one_file_item(char *, char *, FILE **);
  33.  
  34. /* TW's static string consolidation campaign to help brain-dead compilers */
  35. char s_cantwrite[]      = {"Can't write %s"};
  36. char s_cantcreate[]     = {"Can't create %s"};
  37. char s_cantunderstand[] = {"Can't understand %s"};
  38. char s_cantfind[]       = {"Can't find %s"};
  39.  
  40. #ifndef XFRACT
  41.  
  42. void findpath(char far *filename, char *fullpathname) /* return full pathnames */
  43. {
  44.    char fname[FILE_MAX_FNAME];
  45.    char ext[FILE_MAX_EXT];
  46.    char temp_path[FILE_MAX_PATH];
  47.  
  48.    splitpath(filename ,NULL,NULL,fname,ext);
  49.    makepath(temp_path,""   ,"" ,fname,ext);
  50.  
  51.    if(checkcurdir != 0 && access(temp_path,0)==0) {   /* file exists */
  52.       strcpy(fullpathname,temp_path);
  53.       return;
  54.    }
  55.  
  56.    far_strcpy(temp_path,filename);   /* avoid side effect changes to filename */
  57.  
  58.    if (temp_path[0] == SLASHC || (temp_path[0] && temp_path[1] == ':')) {
  59.       if(access(temp_path,0)==0) {   /* file exists */
  60.          strcpy(fullpathname,temp_path);
  61.          return;
  62.          }
  63.       else {
  64.          splitpath(temp_path ,NULL,NULL,fname,ext);
  65.          makepath(temp_path,""   ,"" ,fname,ext);
  66.          }
  67.       }
  68.    fullpathname[0] = 0;             /* indicate none found */
  69. /* #ifdef __TURBOC__ */                /* look for the file */
  70. /*   strcpy(fullpathname,searchpath(temp_path)); */
  71. /* #else */
  72.    _searchenv(temp_path,"PATH",fullpathname);
  73. /* #endif */
  74.    if (fullpathname[0] != 0)            /* found it! */
  75.       if (strncmp(&fullpathname[2],SLASHSLASH,2) == 0) /* stupid klooge! */
  76.      strcpy(&fullpathname[3],temp_path);
  77. }
  78. #endif
  79.  
  80.  
  81. void notdiskmsg()
  82. {
  83. static FCODE sorrymsg[]={
  84. "This type may be slow using a real-disk based 'video' mode, but may not \n\
  85. be too bad if you have enough expanded or extended memory. Press <Esc> to \n\
  86. abort if it appears that your disk drive is working too hard."};
  87.    stopmsg(0,sorrymsg);
  88. }
  89.  
  90. /* Wrapping version of putstring for long numbers                         */
  91. /* row     -- pointer to row variable, internally incremented if needed   */
  92. /* col1    -- starting column                                             */
  93. /* col2    -- last column                                                 */
  94. /* color   -- attribute (same as for putstring)                           */
  95. /* maxrow -- max number of rows to write                                 */
  96. /* returns 0 if success, 1 if hit maxrow before done                      */
  97. int putstringwrap(int *row,int col1,int col2,int color,char far *str,int maxrow)
  98. {
  99.     char save1, save2;
  100.     int length, decpt, padding, startrow, done;
  101.     done = 0;
  102.     startrow = *row;
  103.     length = far_strlen(str);
  104.     padding = 3; /* space between col1 and decimal. */
  105.     /* find decimal point */
  106.     for(decpt=0;decpt < length; decpt++)
  107.        if(str[decpt] == '.')
  108.           break;
  109.     if(decpt >= length)
  110.        decpt = 0;
  111.     if(decpt < padding)
  112.        padding -= decpt;   
  113.     else
  114.        padding = 0;
  115.     col1 += padding;   
  116.     decpt += col1+1; /* column just past where decimal is */         
  117.     while(length > 0)
  118.     {
  119.        if(col2-col1 < length)
  120.        {
  121.           if((*row - startrow + 1) >= maxrow)
  122.              done = 1;
  123.           else
  124.              done = 0;
  125.           save1 = str[col2-col1+1];
  126.           save2 = str[col2-col1+2];
  127.           if(done)
  128.              str[col2-col1+1]   = '+';
  129.           else
  130.              str[col2-col1+1]   = '\\';
  131.           str[col2-col1+2] = 0;
  132.           putstring(*row,col1,color,str);
  133.           if(done == 1)
  134.              break;
  135.           str[col2-col1+1] = save1;
  136.           str[col2-col1+2] = save2;
  137.           str += col2-col1;
  138.           (*row)++;
  139.        } else
  140.           putstring(*row,col1,color,str);
  141.        length -= col2-col1;
  142.        col1 = decpt; /* align with decimal */
  143.     }
  144.     return(done);
  145. }
  146.  
  147. #define rad_to_deg(x) ((x)*(180/PI)) /* most people "think" in degrees */
  148. #define deg_to_rad(x) ((x)*(PI/180))
  149. /*
  150. convert corners to center/mag
  151. Rotation angles indicate how much the IMAGE has been rotated, not the
  152. zoom box.  Same goes for the Skew angles
  153. */
  154.  
  155. #ifdef _MSC_VER
  156. #pragma optimize( "", off )
  157. #endif
  158.  
  159. void cvtcentermag(double *Xctr, double *Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  160. {
  161.    double Width, Height;
  162.    double a, b; /* bottom, left, diagonal */
  163.    double a2, b2, c2; /* squares of above */
  164.    double tmpx, tmpy, tmpa; /* temporary x, y, angle */
  165.  
  166.    /* simple normal case first */
  167.    if (xx3rd == xxmin && yy3rd == yymin)
  168.    { /* no rotation or skewing, but stretching is allowed */
  169.       Width  = xxmax - xxmin;
  170.       Height = yymax - yymin;
  171.       *Xctr = (xxmin + xxmax)/2;
  172.       *Yctr = (yymin + yymax)/2;
  173.       *Magnification  = 2/Height;
  174.       *Xmagfactor =  Height / (DEFAULTASPECT * Width);
  175.       *Rotation = 0.0;
  176.       *Skew = 0.0;
  177.       if (*Magnification < 0)
  178.       {
  179.          *Magnification = -*Magnification;
  180.          *Rotation += 180;
  181.       }
  182.       return;
  183.    }
  184.  
  185.    /* set up triangle ABC, having sides abc */
  186.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  187.    tmpx = xxmax - xx3rd;
  188.    tmpy = yymin - yy3rd;
  189.    a2 = tmpx*tmpx + tmpy*tmpy;
  190.    a = sqrt(a2);
  191.    *Rotation = -rad_to_deg(atan2( tmpy, tmpx )); /* negative for image rotation */
  192.  
  193.    tmpx = xxmin - xx3rd;
  194.    tmpy = yymax - yy3rd;
  195.    b2 = tmpx*tmpx + tmpy*tmpy;
  196.    b = sqrt(b2);
  197.  
  198.    tmpx = xxmax - xxmin;
  199.    tmpy = yymax - yymin;
  200.    c2 = tmpx*tmpx + tmpy*tmpy;
  201.  
  202.    tmpa = acos((a2+b2-c2)/(2*a*b)); /* save tmpa for later use */
  203.    *Skew = 90 - rad_to_deg(tmpa);
  204.  
  205.    *Xctr = (xxmin + xxmax)/2;
  206.    *Yctr = (yymin + yymax)/2;
  207.  
  208.    Height = b * sin(tmpa);
  209.    *Magnification  = 2/Height; /* 1/(h/2) */
  210.    *Xmagfactor = Height / (DEFAULTASPECT * a);
  211.    if (*Magnification < 0)
  212.       {
  213.       *Magnification = -*Magnification;
  214.       *Rotation += 180;
  215.       }
  216.    return;
  217. }
  218.  
  219. /* convert center/mag to corners */
  220. void cvtcorners(double Xctr, double Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  221. {
  222.    double x, y;
  223.    double h, w; /* half height, width */
  224.    double tanskew, sinrot, cosrot;
  225.  
  226.    if (Xmagfactor == 0.0)
  227.       Xmagfactor = 1.0;
  228.  
  229.    h = (double)(1/Magnification);
  230.    w = h / (DEFAULTASPECT * Xmagfactor);
  231.  
  232.    if (Rotation == 0.0 && Skew == 0.0)
  233.       { /* simple, faster case */
  234.       xx3rd = xxmin = Xctr - w;
  235.       xxmax = Xctr + w;
  236.       yy3rd = yymin = Yctr - h;
  237.       yymax = Yctr + h;
  238.       return;
  239.       }
  240.  
  241.    /* in unrotated, untranslated coordinate system */
  242.    tanskew = tan(deg_to_rad(Skew));
  243.    xxmin = -w + h*tanskew;
  244.    xxmax =  w - h*tanskew;
  245.    xx3rd = -w - h*tanskew;
  246.    yymax = h;
  247.    yy3rd = yymin = -h;
  248.  
  249.    /* rotate coord system and then translate it */
  250.    Rotation = deg_to_rad(Rotation);
  251.    sinrot = sin(Rotation);
  252.    cosrot = cos(Rotation);
  253.  
  254.    /* top left */
  255.    x = xxmin * cosrot + yymax *  sinrot;
  256.    y = -xxmin * sinrot + yymax *  cosrot;
  257.    xxmin = x + Xctr;
  258.    yymax = y + Yctr;
  259.  
  260.    /* bottom right */
  261.    x = xxmax * cosrot + yymin *  sinrot;
  262.    y = -xxmax * sinrot + yymin *  cosrot;
  263.    xxmax = x + Xctr;
  264.    yymin = y + Yctr;
  265.  
  266.    /* bottom left */
  267.    x = xx3rd * cosrot + yy3rd *  sinrot;
  268.    y = -xx3rd * sinrot + yy3rd *  cosrot;
  269.    xx3rd = x + Xctr;
  270.    yy3rd = y + Yctr;
  271.  
  272.    return;
  273. }
  274.  
  275. /* convert corners to center/mag using bf */
  276. void cvtcentermagbf(bf_t Xctr, bf_t Yctr, LDBL *Magnification, double *Xmagfactor, double *Rotation, double *Skew)
  277. {
  278.    /* needs to be LDBL or won't work past 307 (-DBL_MIN_10_EXP) or so digits */
  279.    LDBL Width, Height;
  280.    LDBL a, b; /* bottom, left, diagonal */
  281.    LDBL a2, b2, c2; /* squares of above */
  282.    LDBL tmpx, tmpy;
  283.    double tmpa; /* temporary x, y, angle */
  284.    bf_t bfWidth, bfHeight;
  285.    bf_t bftmpx, bftmpy;
  286.    int saved;
  287.    int signx;
  288.  
  289.    saved = save_stack();
  290.  
  291.    /* simple normal case first */
  292.    /* if (xx3rd == xxmin && yy3rd == yymin) */
  293.    if(!cmp_bf(bfx3rd, bfxmin) && !cmp_bf(bfy3rd, bfymin))
  294.       { /* no rotation or skewing, but stretching is allowed */
  295.       bfWidth  = alloc_stack(bflength+2);
  296.       bfHeight = alloc_stack(bflength+2);
  297.       /* Width  = xxmax - xxmin; */
  298.       sub_bf(bfWidth, bfxmax, bfxmin);
  299.       Width  = bftofloat(bfWidth);
  300.       /* Height = yymax - yymin; */
  301.       sub_bf(bfHeight, bfymax, bfymin);
  302.       Height = bftofloat(bfHeight);
  303.       /* *Xctr = (xxmin + xxmax)/2; */
  304.       add_bf(Xctr, bfxmin, bfxmax);
  305.       half_a_bf(Xctr);
  306.       /* *Yctr = (yymin + yymax)/2; */
  307.       add_bf(Yctr, bfymin, bfymax);
  308.       half_a_bf(Yctr);
  309.       *Magnification  = 2/Height;
  310.       *Xmagfactor =  (double)(Height / (DEFAULTASPECT * Width));
  311.       *Rotation = 0.0;
  312.       *Skew = 0.0;
  313.       if (*Magnification < 0)
  314.          {
  315.          *Magnification = -*Magnification;
  316.          *Rotation += 180;
  317.          }
  318.       restore_stack(saved);
  319.       return;
  320.       }
  321.  
  322.    bftmpx = alloc_stack(bflength+2);
  323.    bftmpy = alloc_stack(bflength+2);
  324.  
  325.    /* set up triangle ABC, having sides abc */
  326.    /* side a = bottom, b = left, c = diagonal not containing (x3rd,y3rd) */
  327.    /* IMPORTANT: convert from bf AFTER subtracting */
  328.    /* tmpx = xxmax - xx3rd; */
  329.    sub_bf(bftmpx, bfxmax, bfx3rd);
  330.    tmpx = bftofloat(bftmpx);
  331.    /* tmpy = yymin - yy3rd; */
  332.    sub_bf(bftmpy, bfymin, bfy3rd);
  333.    tmpy = bftofloat(bftmpy);
  334.    a2 = tmpx*tmpx + tmpy*tmpy;
  335.    a = sqrtl(a2);
  336.  
  337.    /* divide tmpx and tmpy by |tmpx| so that double version of atan2() can be used */
  338.    /* atan2() only depends on the ratio, this puts it in double's range */
  339.    signx = sign(tmpx);
  340.    if(signx)
  341.       tmpy /= tmpx * signx;       /* tmpy = tmpy / |tmpx| */
  342.    *Rotation = (double)(-rad_to_deg(atan2( (double)tmpy, signx ))); /* negative for image rotation */
  343.  
  344.    /* tmpx = xxmin - xx3rd; */
  345.    sub_bf(bftmpx, bfxmin, bfx3rd);
  346.    tmpx = bftofloat(bftmpx);
  347.    /* tmpy = yymax - yy3rd; */
  348.    sub_bf(bftmpy, bfymax, bfy3rd);
  349.    tmpy = bftofloat(bftmpy);
  350.    b2 = tmpx*tmpx + tmpy*tmpy;
  351.    b = sqrtl(b2);
  352.  
  353.    /* tmpx = xxmax - xxmin; */
  354.    sub_bf(bftmpx, bfxmax, bfxmin);
  355.    tmpx = bftofloat(bftmpx);
  356.    /* tmpy = yymax - yymin; */
  357.    sub_bf(bftmpy, bfymax, bfymin);
  358.    tmpy = bftofloat(bftmpy);
  359.    c2 = tmpx*tmpx + tmpy*tmpy;
  360.  
  361.    tmpa = acos((double)((a2+b2-c2)/(2*a*b))); /* save tmpa for later use */
  362.    *Skew = 90 - rad_to_deg(tmpa);
  363.  
  364.    /* these are the only two variables that must be to big precision */
  365.    /* *Xctr = (xxmin + xxmax)/2; */
  366.    add_bf(Xctr, bfxmin, bfxmax);
  367.    half_a_bf(Xctr);
  368.    /* *Yctr = (yymin + yymax)/2; */
  369.    add_bf(Yctr, bfymin, bfymax);
  370.    half_a_bf(Yctr);
  371.  
  372.    Height = b * sin(tmpa);
  373.    *Magnification  = 2/Height; /* 1/(h/2) */
  374.    *Xmagfactor = (double)(Height / (DEFAULTASPECT * a));
  375.    if (*Magnification < 0)
  376.       {
  377.       *Magnification = -*Magnification;
  378.       *Rotation += 180;
  379.       }
  380.    restore_stack(saved);
  381.    return;
  382. }
  383.  
  384.  
  385. /* convert center/mag to corners using bf */
  386. void cvtcornersbf(bf_t Xctr, bf_t Yctr, LDBL Magnification, double Xmagfactor, double Rotation, double Skew)
  387. {
  388.    LDBL x, y;
  389.    LDBL h, w; /* half height, width */
  390.    LDBL xmin, ymin, xmax, ymax, x3rd, y3rd;
  391.    double tanskew, sinrot, cosrot;
  392.    bf_t bfh, bfw;
  393.    bf_t bftmp;
  394.    int saved;
  395.  
  396.    saved = save_stack();
  397.    bfh = alloc_stack(bflength+2);
  398.    bfw = alloc_stack(bflength+2);
  399.  
  400.    if (Xmagfactor == 0.0)
  401.       Xmagfactor = 1.0;
  402.  
  403.    h = 1/Magnification;
  404.    floattobf(bfh, h);
  405.    w = h / (DEFAULTASPECT * Xmagfactor);
  406.    floattobf(bfw, w);
  407.  
  408.    if (Rotation == 0.0 && Skew == 0.0)
  409.       { /* simple, faster case */
  410.       /* xx3rd = xxmin = Xctr - w; */
  411.       sub_bf(bfxmin, Xctr, bfw);
  412.       copy_bf(bfx3rd, bfxmin);
  413.       /* xxmax = Xctr + w; */
  414.       add_bf(bfxmax, Xctr, bfw);
  415.       /* yy3rd = yymin = Yctr - h; */
  416.       sub_bf(bfymin, Yctr, bfh);
  417.       copy_bf(bfy3rd, bfymin);
  418.       /* yymax = Yctr + h; */
  419.       add_bf(bfymax, Yctr, bfh);
  420.       restore_stack(saved);
  421.       return;
  422.       }
  423.  
  424.    bftmp = alloc_stack(bflength+2);
  425.    /* in unrotated, untranslated coordinate system */
  426.    tanskew = tan(deg_to_rad(Skew));
  427.    xmin = -w + h*tanskew;
  428.    xmax =  w - h*tanskew;
  429.    x3rd = -w - h*tanskew;
  430.    ymax = h;
  431.    y3rd = ymin = -h;
  432.  
  433.    /* rotate coord system and then translate it */
  434.    Rotation = deg_to_rad(Rotation);
  435.    sinrot = sin(Rotation);
  436.    cosrot = cos(Rotation);
  437.  
  438.    /* top left */
  439.    x =  xmin * cosrot + ymax *  sinrot;
  440.    y = -xmin * sinrot + ymax *  cosrot;
  441.    /* xxmin = x + Xctr; */
  442.    floattobf(bftmp, x);
  443.    add_bf(bfxmin, bftmp, Xctr);
  444.    /* yymax = y + Yctr; */
  445.    floattobf(bftmp, y);
  446.    add_bf(bfymax, bftmp, Yctr);
  447.  
  448.    /* bottom right */
  449.    x =  xmax * cosrot + ymin *  sinrot;
  450.    y = -xmax * sinrot + ymin *  cosrot;
  451.    /* xxmax = x + Xctr; */
  452.    floattobf(bftmp, x);
  453.    add_bf(bfxmax, bftmp, Xctr);
  454.    /* yymin = y + Yctr; */
  455.    floattobf(bftmp, y);
  456.    add_bf(bfymin, bftmp, Yctr);
  457.  
  458.    /* bottom left */
  459.    x =  x3rd * cosrot + y3rd *  sinrot;
  460.    y = -x3rd * sinrot + y3rd *  cosrot;
  461.    /* xx3rd = x + Xctr; */
  462.    floattobf(bftmp, x);
  463.    add_bf(bfx3rd, bftmp, Xctr);
  464.    /* yy3rd = y + Yctr; */
  465.    floattobf(bftmp, y);
  466.    add_bf(bfy3rd, bftmp, Yctr);
  467.  
  468.    restore_stack(saved);
  469.    return;
  470. }
  471.  
  472. #ifdef _MSC_VER
  473. #pragma optimize( "", on )
  474. #endif
  475.  
  476. void updatesavename(char *filename) /* go to the next file name */
  477. {
  478.    char *save, *hold;
  479.    char name[80];
  480.    char drive[FILE_MAX_DRIVE];
  481.    char dir[FILE_MAX_DIR];
  482.    char fname[FILE_MAX_FNAME];
  483.    char ext[FILE_MAX_EXT];
  484.  
  485.    splitpath(filename ,drive,dir,fname,ext);
  486.    makepath(name,""   ,"" ,fname,ext);
  487.  
  488.    suffix[0] = 0;
  489.  
  490.    hold = name + strlen(name) - 1; /* start at the end */
  491.    while(hold >= name && (*hold == ' ' || isdigit(*hold))) /* skip backwards */
  492.       hold--;
  493.    hold++;            /* recover first digit */
  494.    while (*hold == '0')         /* skip leading zeros */
  495.       hold++;
  496.    save = hold;
  497.    while (*save) {        /* check for all nines */
  498.       if (*save != '9')
  499.      break;
  500.       save++;
  501.       }
  502.    if (!*save)            /* if the whole thing is nines then back */
  503.       save = hold - 1;        /* up one place. Note that this will eat */
  504.                 /* your last letter if you go to far.     */
  505.    else
  506.       save = hold;
  507.    sprintf(save,"%d",atoi(hold)+1); /* increment the number */
  508.    splitpath(name ,NULL,NULL,fname,ext);
  509.    makepath(filename,drive,dir,fname,ext);
  510. }
  511.  
  512. int check_writefile(char *name,char *ext)
  513. {
  514.  /* after v16 release, change encoder.c to also use this routine */
  515.    char openfile[80];
  516.    char opentype[20];
  517.  /* int i; */
  518.    char *period;
  519. nextname:
  520.    strcpy(openfile,name);
  521.    strcpy(opentype,ext);
  522. #if 0   
  523.    for (i = 0; i < (int)strlen(openfile); i++)
  524.       if (openfile[i] == '.') {
  525.      strcpy(opentype,&openfile[i]);
  526.      openfile[i] = 0;
  527.      }
  528. #endif
  529.    if((period = has_ext(openfile)) != NULL)
  530.    {
  531.       strcpy(opentype,period);
  532.       *period = 0;
  533.    }        
  534.    strcat(openfile,opentype);
  535.    if (access(openfile,0) != 0) /* file doesn't exist */
  536.    {
  537.       strcpy(name,openfile);
  538.       return 0;
  539.     }
  540.    /* file already exists */
  541.    if (overwrite == 0) {
  542.       updatesavename(name);
  543.       goto nextname;
  544.       }
  545.    return 1;
  546. }
  547.  
  548. /* ('check_key()' was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  549. /* ('timer()'     was moved to FRACTINT.C for MSC7-overlay speed purposes) */
  550.  
  551. BYTE trigndx[] = {SIN,SQR,SINH,COSH};
  552. #ifndef XFRACT
  553. void (*ltrig0)(void) = lStkSin;
  554. void (*ltrig1)(void) = lStkSqr;
  555. void (*ltrig2)(void) = lStkSinh;
  556. void (*ltrig3)(void) = lStkCosh;
  557. void (*mtrig0)(void) = mStkSin;
  558. void (*mtrig1)(void) = mStkSqr;
  559. void (*mtrig2)(void) = mStkSinh;
  560. void (*mtrig3)(void) = mStkCosh;
  561. #endif
  562. void (*dtrig0)(void) = dStkSin;
  563. void (*dtrig1)(void) = dStkSqr;
  564. void (*dtrig2)(void) = dStkSinh;
  565. void (*dtrig3)(void) = dStkCosh;
  566.  
  567. struct trig_funct_lst trigfn[] =
  568. /* changing the order of these alters meaning of *.fra file */
  569. /* maximum 6 characters in function names or recheck all related code */
  570. {
  571. #ifndef XFRACT
  572.    {s_sin,   lStkSin,   dStkSin,   mStkSin   },
  573.    {s_cosxx, lStkCosXX, dStkCosXX, mStkCosXX },
  574.    {s_sinh,  lStkSinh,  dStkSinh,  mStkSinh  },
  575.    {s_cosh,  lStkCosh,  dStkCosh,  mStkCosh  },
  576.    {s_exp,   lStkExp,   dStkExp,   mStkExp   },
  577.    {s_log,   lStkLog,   dStkLog,   mStkLog   },
  578.    {s_sqr,   lStkSqr,   dStkSqr,   mStkSqr   },
  579.    {s_recip, lStkRecip, dStkRecip, mStkRecip }, /* from recip on new in v16 */
  580.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  581.    {s_cos,   lStkCos,   dStkCos,   mStkCos   },
  582.    {s_tan,   lStkTan,   dStkTan,   mStkTan   },
  583.    {s_tanh,  lStkTanh,  dStkTanh,  mStkTanh  },
  584.    {s_cotan, lStkCoTan, dStkCoTan, mStkCoTan },
  585.    {s_cotanh,lStkCoTanh,dStkCoTanh,mStkCoTanh},
  586.    {s_flip,  lStkFlip,  dStkFlip,  mStkFlip  },
  587.    {s_conj,  lStkConj,  dStkConj,  mStkConj  },
  588.    {s_zero,  lStkZero,  dStkZero,  mStkZero  },
  589.    {s_asin,  lStkASin,  dStkASin,  mStkASin  },
  590.    {s_asinh, lStkASinh, dStkASinh, mStkASinh },
  591.    {s_acos,  lStkACos,  dStkACos,  mStkACos  },
  592.    {s_acosh, lStkACosh, dStkACosh, mStkACosh },
  593.    {s_atan,  lStkATan,  dStkATan,  mStkATan  },
  594.    {s_atanh, lStkATanh, dStkATanh, mStkATanh },
  595.    {s_cabs,  lStkCAbs,  dStkCAbs,  mStkCAbs  },
  596.    {s_abs,   lStkAbs,   dStkAbs,   mStkAbs   },
  597.    {s_sqrt,  lStkSqrt,  dStkSqrt,  mStkSqrt  },
  598. #else
  599.    {s_sin,   dStkSin,   dStkSin,   dStkSin   },
  600.    {s_cosxx, dStkCosXX, dStkCosXX, dStkCosXX },
  601.    {s_sinh,  dStkSinh,  dStkSinh,  dStkSinh  },
  602.    {s_cosh,  dStkCosh,  dStkCosh,  dStkCosh  },
  603.    {s_exp,   dStkExp,   dStkExp,   dStkExp   },
  604.    {s_log,   dStkLog,   dStkLog,   dStkLog   },
  605.    {s_sqr,   dStkSqr,   dStkSqr,   dStkSqr   },
  606.    {s_recip, dStkRecip, dStkRecip, dStkRecip }, /* from recip on new in v16 */
  607.    {s_ident, StkIdent,  StkIdent,  StkIdent  },
  608.    {s_cos,   dStkCos,   dStkCos,   dStkCos   },
  609.    {s_tan,   dStkTan,   dStkTan,   dStkTan   },
  610.    {s_tanh,  dStkTanh,  dStkTanh,  dStkTanh  },
  611.    {s_cotan, dStkCoTan, dStkCoTan, dStkCoTan },
  612.    {s_cotanh,dStkCoTanh,dStkCoTanh,dStkCoTanh},
  613.    {s_flip,  dStkFlip,  dStkFlip,  dStkFlip  },
  614.    {s_conj,  dStkConj,  dStkConj,  dStkConj  },
  615.    {s_zero,  dStkZero,  dStkZero,  dStkZero  },
  616.    {s_asin,  dStkASin,  dStkASin,  dStkASin  },
  617.    {s_asinh, dStkASinh, dStkASinh, dStkASinh },
  618.    {s_acos,  dStkACos,  dStkACos,  dStkACos  },
  619.    {s_acosh, dStkACosh, dStkACosh, dStkACosh },
  620.    {s_atan,  dStkATan,  dStkATan,  dStkATan  },
  621.    {s_atanh, dStkATanh, dStkATanh, dStkATanh },
  622.    {s_cabs,  dStkCAbs,  dStkCAbs,  dStkCAbs  },
  623.    {s_abs,   dStkAbs,   dStkAbs,   dStkAbs   },
  624.    {s_sqrt,  dStkSqrt,  dStkSqrt,  dStkSqrt  },
  625. #endif
  626. };
  627. int numtrigfn = sizeof(trigfn)/sizeof(struct trig_funct_lst);
  628.  
  629. void showtrig(char *buf) /* return display form of active trig functions */
  630. {
  631.    char tmpbuf[30];
  632.    *buf = 0; /* null string if none */
  633.    trigdetails(tmpbuf);
  634.    if (tmpbuf[0])
  635.       sprintf(buf," function=%s",tmpbuf);
  636. }
  637.  
  638. static void trigdetails(char *buf)
  639. {
  640.    int i, numfn;
  641.    char tmpbuf[20];
  642.    if(fractype==JULIBROT || fractype==JULIBROTFP)
  643.       numfn = (fractalspecific[neworbittype].flags >> 6) & 7;
  644.    else
  645.       numfn = (curfractalspecific->flags >> 6) & 7;
  646.    if(curfractalspecific == &fractalspecific[FORMULA] ||
  647.       curfractalspecific == &fractalspecific[FFORMULA]    )
  648.       numfn = maxfn;
  649.    *buf = 0; /* null string if none */
  650.    if (numfn>0) {
  651.       strcpy(buf,trigfn[trigndx[0]].name);
  652.       i = 0;
  653.       while(++i < numfn) {
  654.      sprintf(tmpbuf,"/%s",trigfn[trigndx[i]].name);
  655.      strcat(buf,tmpbuf);
  656.      }
  657.       }
  658. }
  659.  
  660. /* set array of trig function indices according to "function=" command */
  661. int set_trig_array(int k, char *name)
  662. {
  663.    char trigname[10];
  664.    int i;
  665.    char *slash;
  666.    strncpy(trigname,name,6);
  667.    trigname[6] = 0; /* safety first */
  668.  
  669.    if ((slash = strchr(trigname,'/')) != NULL)
  670.       *slash = 0;
  671.  
  672.    strlwr(trigname);
  673.  
  674.    for(i=0;i<numtrigfn;i++)
  675.    {
  676.       if(strcmp(trigname,trigfn[i].name)==0)
  677.       {
  678.      trigndx[k] = (BYTE)i;
  679.      set_trig_pointers(k);
  680.      break;
  681.       }
  682.    }
  683.    return(0);
  684. }
  685. void set_trig_pointers(int which)
  686. {
  687.   /* set trig variable functions to avoid array lookup time */
  688.    int i;
  689.    switch(which)
  690.    {
  691.    case 0:
  692. #ifndef XFRACT
  693.       ltrig0 = trigfn[trigndx[0]].lfunct;
  694.       mtrig0 = trigfn[trigndx[0]].mfunct;
  695. #endif
  696.       dtrig0 = trigfn[trigndx[0]].dfunct;
  697.       break;
  698.    case 1:
  699. #ifndef XFRACT
  700.       ltrig1 = trigfn[trigndx[1]].lfunct;
  701.       mtrig1 = trigfn[trigndx[1]].mfunct;
  702. #endif
  703.       dtrig1 = trigfn[trigndx[1]].dfunct;
  704.       break;
  705.    case 2:
  706. #ifndef XFRACT
  707.       ltrig2 = trigfn[trigndx[2]].lfunct;
  708.       mtrig2 = trigfn[trigndx[2]].mfunct;
  709. #endif
  710.       dtrig2 = trigfn[trigndx[2]].dfunct;
  711.       break;
  712.    case 3:
  713. #ifndef XFRACT
  714.       ltrig3 = trigfn[trigndx[3]].lfunct;
  715.       mtrig3 = trigfn[trigndx[3]].mfunct;
  716. #endif
  717.       dtrig3 = trigfn[trigndx[3]].dfunct;
  718.       break;
  719.    default: /* do 'em all */
  720.       for(i=0;i<4;i++)
  721.      set_trig_pointers(i);
  722.       break;
  723.    }
  724. }
  725.  
  726. static FCODE sfractal_type[] =     {"Fractal type:"};
  727. static FCODE sitem_name[] =        {"Item name:"};
  728. static FCODE sitem_file[] =        {"Item file:"};
  729. static FCODE s3D_transform[] =     {"3D Transform"};
  730. static FCODE syou_are_cycling[] =  {"You are in color-cycling mode"};
  731. static FCODE sfloating_point[] =   {"Floating-point"};
  732. static FCODE ssolid_guessing[] =   {"Solid Guessing"};
  733. static FCODE sboundary_tracing[] = {"Boundary Tracing"};
  734. static FCODE stesseral[] =         {"Tesseral"};
  735. static FCODE scalculation_time[] = {"Calculation time:"};
  736. static FCODE siterations[] =       {" 1000's of points:"};
  737. static FCODE scornersxy[] =        {"Corners:                X                     Y"};
  738. static FCODE stop_left[] =         {"Top-l"};
  739. static FCODE sbottom_right[] =     {"Bot-r"};
  740. static FCODE sbottom_left[] =      {"Bot-l"};
  741. static FCODE scenter[] =           {"Ctr"};
  742. static FCODE struncate[] =         {"(Center values shown truncated to 320 decimals)"};
  743. static FCODE smag[] =              {"Mag"};
  744. static FCODE sxmag[] =             {"X-Mag-Factor"};
  745. static FCODE srot[] =              {"Rotation"};
  746. static FCODE sskew[] =             {"Skew"};
  747. static FCODE sparams[] =           {"Params "};
  748. static FCODE siteration_maximum[] ={"Iteration maximum: "};
  749. static FCODE seffective_bailout[] ={"     Effective bailout: "};
  750. static FCODE scurrent_rseed[] =    {"Current 'rseed': "};
  751. static FCODE sinversion_radius[] = {"Inversion radius: "};
  752. static FCODE sxcenter[] =          {"  xcenter: "};
  753. static FCODE sycenter[] =          {"  ycenter: "};
  754. static FCODE sparms_chgd[] = {"Parms chgd since generated"};
  755. static FCODE sstill_being[] = {"Still being generated"};
  756. static FCODE sinterrupted_resumable[] = {"Interrupted, resumable"};
  757. static FCODE sinterrupted_non_resumable[] = {"Interrupted, non-resumable"};
  758. static FCODE simage_completed[] = {"Image completed"};
  759. static FCODE sflag_is_activated[] = {" flag is activated"};
  760. static FCODE sinteger_math[]      = {"Integer math is in use"};
  761. static FCODE sin_use_required[] = {" in use (required)"};
  762. static FCODE sarbitrary_precision[] = {"Arbitrary precision "};
  763. static FCODE spressanykey[] = {"Press any key to continue, F6 for area, CTRL-TAB for next page"};
  764. static FCODE spressanykey1[] = {"Press any key to continue, Backspace for first screen"};
  765. static FCODE sbatch[] = {" (Batch mode)"};
  766. static FCODE ssavename[] = {"Savename: "};
  767. static FCODE sstopsecret[] = {"Top Secret Developer's Screen"};
  768. static FCODE sthreepass[] = {" (threepass)"};   
  769.  
  770. static void show_str_var(char *name, char *var, int *row, char *msg)
  771. {
  772.    if(var == NULL)
  773.       return;
  774.    if(*var != 0)
  775.    {
  776.       sprintf(msg,"%s=%s",name,var);
  777.       putstring((*row)++,2,C_GENERAL_HI,msg);
  778.    }
  779. }
  780.  
  781. int tab_display_2(char *msg)
  782. {
  783.    extern long maxptr, maxstack, startstack;
  784.    int row,key,ret=0;
  785.    helptitle();
  786.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  787.  
  788.    row = 1;
  789.    putstringcenter(row++,0,80,C_PROMPT_HI, sstopsecret);
  790.    sprintf(msg,"%u bytes conventional stack free",stackavail());
  791.    putstring(++row,2,C_GENERAL_HI,msg);
  792.    sprintf(msg,"%ld of %ld bignum memory used",maxptr,maxstack);
  793.    putstring(++row,2,C_GENERAL_HI,msg);
  794.    sprintf(msg,"   %ld used for bignum globals", startstack);
  795.    putstring(++row,2,C_GENERAL_HI,msg);
  796.    sprintf(msg,"   %ld stack used == %ld variables of length %d",
  797.          maxptr-startstack,(long)((maxptr-startstack)/(rbflength+2)),rbflength+2);
  798.    putstring(++row,2,C_GENERAL_HI,msg);
  799.    if(bf_math)
  800.    {
  801.       sprintf(msg,"intlength %-d bflength %-d ",intlength, bflength);
  802.       putstring(++row,2,C_GENERAL_HI,msg);
  803.    }
  804.    row++;   
  805.    show_str_var(s_tempdir,    tempdir,      &row, msg);
  806.    show_str_var(s_workdir,    workdir,      &row, msg);
  807.    show_str_var(s_printfile,  PrintName,    &row, msg);
  808.    show_str_var(s_filename,   readname,     &row, msg);
  809.    show_str_var(s_formulafile,FormFileName, &row, msg);
  810.    show_str_var(s_savename,   savename,     &row, msg);
  811.    show_str_var(s_parmfile,   CommandFile,  &row, msg);
  812.    show_str_var(s_ifsfile,    IFSFileName,  &row, msg);
  813.    show_str_var(s_autokeyname,autoname,     &row, msg);
  814.    show_str_var(s_lightname,  light_name,   &row, msg);
  815.    show_str_var(s_map,        MAP_name,     &row, msg);
  816.    sprintf(msg,"Sizeof fractalspecific array %d",
  817.       num_fractal_types*(int)sizeof(struct fractalspecificstuff));
  818.    putstring(row++,2,C_GENERAL_HI,msg);
  819.    sprintf(msg,"checkcurdir %d",checkcurdir);
  820.    putstring(row++,2,C_GENERAL_HI,msg);
  821.    sprintf(msg,"calc_status %d",calc_status);
  822.    putstring(row++,2,C_GENERAL_HI,msg);
  823.  
  824.    putstringcenter(24,0,80,C_GENERAL_LO,spressanykey1);
  825.    key=getakeynohelp();
  826.    if(key == BACKSPACE)
  827.       ret = 1;
  828.    return(ret);      
  829. }
  830.  
  831. int tab_display()    /* display the status of the current image */
  832. {
  833.    int row, i, j, addrow=0;
  834.    double Xctr, Yctr;
  835.    LDBL Magnification;
  836.    double Xmagfactor, Rotation, Skew;
  837.    bf_t bfXctr=NULL, bfYctr=NULL;
  838.    char msg[350];
  839.    char far *msgptr;
  840.    int key;
  841.    int saved=0;
  842.    int dec;
  843.  
  844.    if (calc_status < 0) {     /* no active fractal image */
  845.       return(0);        /* (no TAB on the credits screen) */
  846.    }
  847.    if (calc_status == 1)    /* next assumes CLK_TCK is 10^n, n>=2 */
  848.       calctime += (clock_ticks() - timer_start) / (CLK_TCK/100);
  849.    stackscreen();
  850.    if(bf_math)
  851.    {
  852.       saved = save_stack();
  853.       bfXctr = alloc_stack(bflength+2);
  854.       bfYctr = alloc_stack(bflength+2);
  855.    }
  856. top:
  857.    helptitle();
  858.    setattr(1,0,C_GENERAL_MED,24*80); /* init rest to background */
  859.    row = 2;
  860.    putstring(row,2,C_GENERAL_MED,sfractal_type);
  861.    if (display3d > 0)
  862.       putstring(row,16,C_GENERAL_HI,s3D_transform);
  863.    else {
  864.       putstring(row,16,C_GENERAL_HI,
  865.        curfractalspecific->name[0] == '*' ?
  866.          &curfractalspecific->name[1] :
  867.          curfractalspecific->name);
  868.       i = 0;
  869.       if (fractype == FORMULA || fractype == FFORMULA)
  870.       {
  871.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  872.      putstring(row+1,16,C_GENERAL_HI,FormName);
  873.          i = strlen(FormName)+1;
  874.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  875.          if(strlen(FormFileName) >= 29)
  876.             addrow = 1;
  877.          putstring(row+2+addrow,16,C_GENERAL_HI,FormFileName);
  878.       }
  879.       trigdetails(msg);
  880.       putstring(row+1,16+i,C_GENERAL_HI,msg);
  881.       if (fractype == LSYSTEM) 
  882.       {
  883.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  884.      putstring(row+1,16,C_GENERAL_HI,LName);
  885.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  886.          if(strlen(LFileName) >= 28)
  887.             addrow = 1;
  888.          putstring(row+2+addrow,16,C_GENERAL_HI,LFileName);
  889.       }
  890.       if (fractype == IFS || fractype == IFS3D) 
  891.       {
  892.          putstring(row+1,3,C_GENERAL_MED,sitem_name);
  893.      putstring(row+1,16,C_GENERAL_HI,IFSName);
  894.          putstring(row+2,3,C_GENERAL_MED,sitem_file);
  895.          if(strlen(IFSFileName) >= 28)
  896.             addrow = 1;
  897.          putstring(row+2+addrow,16,C_GENERAL_HI,IFSFileName);
  898.       }
  899.    }
  900.  
  901.    switch (calc_status) {
  902.       case 0:  msgptr = sparms_chgd;
  903.            break;
  904.       case 1:  msgptr = sstill_being;
  905.            break;
  906.       case 2:  msgptr = sinterrupted_resumable;
  907.            break;
  908.       case 3:  msgptr = sinterrupted_non_resumable;
  909.            break;
  910.       case 4:  msgptr = simage_completed;
  911.            break;
  912.       default: msgptr = "";
  913.       }
  914.    putstring(row,45,C_GENERAL_HI,msgptr);
  915.    if(initbatch && calc_status != 0)
  916.       putstring(-1,-1,C_GENERAL_HI,sbatch);
  917.    
  918.    if (helpmode == HELPCYCLING)
  919.       putstring(row+1,45,C_GENERAL_HI,syou_are_cycling);
  920.    ++row;
  921.    /* if(bf_math == 0) */ 
  922.      ++row;
  923.  
  924.     i = j = 0;
  925.     if (display3d > 0) {
  926.        if (usr_floatflag)
  927.       j = 1;
  928.        }
  929.     else
  930.        if (floatflag)
  931.       j = (usr_floatflag) ? 1 : 2;
  932.     if(bf_math==0)
  933.     {
  934.     if (j) {
  935.        putstring(row,45,C_GENERAL_HI,sfloating_point);
  936.  
  937.        putstring(-1,-1,C_GENERAL_HI,(j == 1) ? sflag_is_activated
  938.                          : sin_use_required );
  939.       i = 1;
  940.       }
  941.       else
  942.       {
  943.        putstring(row,45,C_GENERAL_HI,sinteger_math);
  944.       i = 1;
  945.       }
  946.    } else
  947.    {
  948.        sprintf(msg,"(%-d decimals)",decimals /*getprecbf(CURRENTREZ)*/);
  949.        putstring(row,45,C_GENERAL_HI,sarbitrary_precision);
  950.        putstring(-1,-1,C_GENERAL_HI,msg);
  951.  
  952.       i = 1;
  953.    }   
  954.  
  955.    row += i;
  956.  
  957.    if (calc_status == 1 || calc_status == 2)
  958.       if (curfractalspecific->flags&NORESUME)
  959.       {
  960.      static FCODE msg[] = {"Note: can't resume this type after interrupts other than <tab> and <F1>"};
  961.      putstring(row++,2,C_GENERAL_HI,msg);
  962.       }
  963.    row += addrow;
  964.    putstring(row,2,C_GENERAL_MED,ssavename);
  965.    putstring(row,-1,C_GENERAL_HI,savename);
  966.    
  967.    /* if(bf_math == 0) */
  968.      ++row;
  969.  
  970.    if (got_status >= 0 && (calc_status == 1 || calc_status == 2)) {
  971.       switch (got_status) {
  972.      case 0:
  973.         sprintf(msg,"%d Pass Mode",totpasses);
  974.         putstring(row,2,C_GENERAL_HI,msg);
  975.             if(usr_stdcalcmode=='3')
  976.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  977.         break;
  978.      case 1:
  979.         putstring(row,2,C_GENERAL_HI,ssolid_guessing);
  980.             if(usr_stdcalcmode=='3')
  981.                 putstring(row,-1,C_GENERAL_HI,sthreepass);
  982.         break;
  983.      case 2:
  984.         putstring(row,2,C_GENERAL_HI,sboundary_tracing);
  985.         break;
  986.      case 3:
  987.         sprintf(msg,"Processing row %d (of %d) of input image",currow,fileydots);
  988.         putstring(row,2,C_GENERAL_HI,msg);
  989.         break;
  990.      case 4:
  991.         putstring(row,2,C_GENERAL_HI,stesseral);
  992.         break;
  993.      }
  994.       ++row;
  995.       if (got_status != 3) {
  996.      sprintf(msg,"Working on block (y,x) [%d,%d]...[%d,%d], ",
  997.         yystart,xxstart,yystop,xxstop);
  998.      putstring(row,2,C_GENERAL_MED,msg);
  999.      if (got_status == 2 || got_status == 4) { /* btm or tesseral */
  1000.         putstring(-1,-1,C_GENERAL_MED,"at ");
  1001.         sprintf(msg,"[%d,%d]",currow,curcol);
  1002.         putstring(-1,-1,C_GENERAL_HI,msg);
  1003.         }
  1004.      else {
  1005.         if (totpasses > 1) {
  1006.            putstring(-1,-1,C_GENERAL_MED,"pass ");
  1007.            sprintf(msg,"%d",curpass);
  1008.            putstring(-1,-1,C_GENERAL_HI,msg);
  1009.            putstring(-1,-1,C_GENERAL_MED," of ");
  1010.            sprintf(msg,"%d",totpasses);
  1011.            putstring(-1,-1,C_GENERAL_HI,msg);
  1012.            putstring(-1,-1,C_GENERAL_MED,", ");
  1013.            }
  1014.         putstring(-1,-1,C_GENERAL_MED,"at row ");
  1015.         sprintf(msg,"%d",currow);
  1016.         putstring(-1,-1,C_GENERAL_HI,msg);
  1017.         }
  1018.      ++row;
  1019.      }
  1020.       }
  1021.    putstring(row,2,C_GENERAL_MED,scalculation_time);
  1022.    if (calctime >= 0)
  1023.       sprintf(msg,"%3ld:%02ld:%02ld.%02ld", calctime/360000L,
  1024.              (calctime%360000L)/6000, (calctime%6000)/100, calctime%100);
  1025.    else
  1026.       sprintf(msg," A Really Long Time!!! (> 24.855 days)");
  1027.    putstring(-1,-1,C_GENERAL_HI,msg);
  1028.    /* XXX */
  1029.  
  1030.    if ((curfractalspecific->flags&INFCALC) && (coloriter != 0)) {
  1031.       putstring(row,-1,C_GENERAL_MED,siterations);
  1032.       sprintf(msg," %ld of %ld",coloriter-2,maxct);
  1033.       putstring(row,-1,C_GENERAL_HI,msg);
  1034.    }
  1035.    
  1036.    ++row;
  1037.    if(bf_math == 0)
  1038.      ++row;
  1039.    if (videoentry.xdots && bf_math==0) {
  1040.       sprintf(msg,"Video: %dx%dx%d %s %s",
  1041.           videoentry.xdots, videoentry.ydots, videoentry.colors,
  1042.           videoentry.name, videoentry.comment);
  1043.       putstring(row++,2,C_GENERAL_MED,msg);
  1044.       }
  1045.    if(!(curfractalspecific->flags&NOZOOM))
  1046.    {
  1047.    adjust_corner(); /* make bottom left exact if very near exact */
  1048.    if(bf_math)
  1049.    {
  1050.       int truncate, truncaterow;
  1051.       dec = min(320,decimals);
  1052.       adjust_cornerbf(); /* make bottom left exact if very near exact */
  1053.       cvtcentermagbf(bfXctr, bfYctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1054.       /* find alignment information */
  1055.       msg[0] = 0;
  1056.       truncate = 0;
  1057.       if(dec < decimals)
  1058.          truncate = 1;
  1059.       truncaterow = row;
  1060.       putstring(++row,2,C_GENERAL_MED,scenter);
  1061.       putstring(row,8,C_GENERAL_MED,s_x);
  1062.       bftostr(msg,dec,bfXctr);
  1063.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1)
  1064.          truncate = 1;
  1065.       putstring(++row,8,C_GENERAL_MED,s_y);
  1066.       bftostr(msg,dec,bfYctr);
  1067.       if(putstringwrap(&row,10,78,C_GENERAL_HI,msg,5)==1 || truncate)
  1068.          putstring(truncaterow,2,C_GENERAL_MED,struncate);
  1069.       putstring(++row,2,C_GENERAL_MED,smag);
  1070. #ifdef USE_LONG_DOUBLE
  1071.       sprintf(msg,"%10.8Le",Magnification);
  1072. #else
  1073.       sprintf(msg,"%10.8le",Magnification);
  1074. #endif
  1075.       putstring(-1,11,C_GENERAL_HI,msg);
  1076.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1077.       sprintf(msg,"%11.4f   ",Xmagfactor);
  1078.       putstring(-1,-1,C_GENERAL_HI,msg);
  1079.       putstring(-1,-1,C_GENERAL_MED,srot);
  1080.       sprintf(msg,"%9.3f   ",Rotation);
  1081.       putstring(-1,-1,C_GENERAL_HI,msg);
  1082.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1083.       sprintf(msg,"%9.3f",Skew);
  1084.       putstring(-1,-1,C_GENERAL_HI,msg);
  1085.    }
  1086.    else /* bf != 1 */
  1087.    {
  1088.       putstring(row,2,C_GENERAL_MED,scornersxy);
  1089.       putstring(++row,3,C_GENERAL_MED,stop_left);
  1090.       sprintf(msg,"%20.16f  %20.16f",xxmin,yymax);
  1091.       putstring(-1,17,C_GENERAL_HI,msg);
  1092.       putstring(++row,3,C_GENERAL_MED,sbottom_right);
  1093.       sprintf(msg,"%20.16f  %20.16f",xxmax,yymin);
  1094.       putstring(-1,17,C_GENERAL_HI,msg);
  1095.  
  1096.       if (xxmin != xx3rd || yymin != yy3rd)
  1097.       {
  1098.          putstring(++row,3,C_GENERAL_MED,sbottom_left);
  1099.          sprintf(msg,"%20.16f  %20.16f",xx3rd,yy3rd);
  1100.          putstring(-1,17,C_GENERAL_HI,msg);
  1101.       }
  1102.       cvtcentermag(&Xctr, &Yctr, &Magnification, &Xmagfactor, &Rotation, &Skew);
  1103.       putstring(row+=2,2,C_GENERAL_MED,scenter);
  1104.       sprintf(msg,"%20.16f %20.16f  ",Xctr,Yctr);
  1105.       putstring(-1,-1,C_GENERAL_HI,msg);
  1106.       putstring(-1,-1,C_GENERAL_MED,smag);
  1107. #ifdef USE_LONG_DOUBLE
  1108.       sprintf(msg," %10.8Le",Magnification);
  1109. #else
  1110.       sprintf(msg," %10.8le",Magnification);
  1111. #endif
  1112.       putstring(-1,-1,C_GENERAL_HI,msg);
  1113.       putstring(++row,2,C_GENERAL_MED,sxmag);
  1114.       sprintf(msg,"%11.4f   ",Xmagfactor);
  1115.       putstring(-1,-1,C_GENERAL_HI,msg);
  1116.       putstring(-1,-1,C_GENERAL_MED,srot);
  1117.       sprintf(msg,"%9.3f   ",Rotation);
  1118.       putstring(-1,-1,C_GENERAL_HI,msg);
  1119.       putstring(-1,-1,C_GENERAL_MED,sskew);
  1120.       sprintf(msg,"%9.3f",Skew);
  1121.       putstring(-1,-1,C_GENERAL_HI,msg);
  1122.  
  1123.    }
  1124.    }      
  1125.    for (i = 0; i < MAXPARAMS; i++)
  1126.    {
  1127.       char *p;
  1128.       int col;
  1129.       p = typehasparm(fractype,i);
  1130.       if(i%4 == 0)
  1131.       {
  1132.          row++;
  1133.          col = 9;
  1134.       }
  1135.       else
  1136.          col = -1;
  1137.       if(p)
  1138.       {
  1139.          if(i==0)
  1140.             putstring(++row,2,C_GENERAL_MED,sparams);
  1141.          sprintf(msg,"%3d: ",i+1);
  1142.          putstring(row,col,C_GENERAL_MED,msg);
  1143.          if(*p == '+')
  1144.             sprintf(msg,"%-12d",(int)param[i]);
  1145.          else if(*p == '#')
  1146.             sprintf(msg,"%-12lu",(U32)param[i]);
  1147.          else   
  1148.             sprintf(msg,"%-12.9f",param[i]);
  1149.          putstring(-1,-1,C_GENERAL_HI,msg);
  1150.       }
  1151.    }
  1152.    putstring(row+=2,2,C_GENERAL_MED,siteration_maximum);
  1153.    sprintf(msg,"%ld",maxit);
  1154.    putstring(-1,-1,C_GENERAL_HI,msg);
  1155.    putstring(-1,-1,C_GENERAL_MED,seffective_bailout);
  1156.    sprintf(msg,"%f",rqlim);
  1157.    putstring(-1,-1,C_GENERAL_HI,msg);
  1158.  
  1159.    if (fractype == PLASMA) {
  1160.       putstring(++row,2,C_GENERAL_MED,scurrent_rseed);
  1161.       sprintf(msg,"%d",rseed);
  1162.       putstring(-1,-1,C_GENERAL_HI,msg);
  1163.       }
  1164.  
  1165.    if(invert) {
  1166.       putstring(++row,2,C_GENERAL_MED,sinversion_radius);
  1167.       sprintf(msg,"%12.9f",f_radius);
  1168.       putstring(-1,-1,C_GENERAL_HI,msg);
  1169.       putstring(-1,-1,C_GENERAL_MED,sxcenter);
  1170.       sprintf(msg,"%12.9f",f_xcenter);
  1171.       putstring(-1,-1,C_GENERAL_HI,msg);
  1172.       putstring(-1,-1,C_GENERAL_MED,sycenter);
  1173.       sprintf(msg,"%12.9f",f_ycenter);
  1174.       putstring(-1,-1,C_GENERAL_HI,msg);
  1175.       }
  1176.  
  1177.    if ((row += 2) < 23) ++row;
  1178. /*waitforkey:*/
  1179.    putstringcenter(/*row*/24,0,80,C_GENERAL_LO,spressanykey);
  1180.    movecursor(25,80);
  1181. #ifdef XFRACT
  1182.    while (keypressed()) {
  1183.        getakey();
  1184.    }
  1185. #endif
  1186.    key = getakeynohelp();
  1187.    if (key==F6) {
  1188.        unstackscreen();
  1189.        area();
  1190.        stackscreen();
  1191. /*       goto waitforkey;*/
  1192.         goto top;
  1193.    }
  1194.    else if(key==CTL_TAB) {    
  1195.       if(tab_display_2(msg))
  1196.          goto top;
  1197.    }
  1198.    unstackscreen();
  1199.    timer_start = clock_ticks(); /* tab display was "time out" */
  1200.    if(bf_math)
  1201.       restore_stack(saved);
  1202.    return(0);
  1203. }
  1204.  
  1205. static void area(void)
  1206. {
  1207.     /* apologies to UNIX folks, we PC guys have to save near space */
  1208.     static FCODE warning[] = {"Warning: inside may not be unique\n"};
  1209.     static FCODE total_area[] = {".  Total area "}; 
  1210.     char far *msg;
  1211.     int x,y;
  1212.     char buf[160];
  1213.     long cnt=0;
  1214.     if (inside<0) {
  1215.       static FCODE msg[] = {"Need solid inside to compute area"};
  1216.       stopmsg(0,msg);
  1217.       return;
  1218.     }
  1219.     for (y=0;y<ydots;y++) {
  1220.       for (x=0;x<xdots;x++) {
  1221.           if (getcolor(x,y)==inside) {
  1222.               cnt++;
  1223.           }
  1224.       }
  1225.     }
  1226.     if (inside>0 && outside<0 && maxit>inside) {
  1227.       msg = warning;
  1228.     } else {
  1229.       msg = (char far *)"";
  1230.     }
  1231. #ifndef XFRACT
  1232.       sprintf(buf,"%Fs%ld inside pixels of %ld%Fs%f",
  1233.               msg,cnt,(long)xdots*(long)ydots,(char far *)total_area,
  1234.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1235. #else
  1236.       sprintf(buf,"%s%ld inside pixels of %ld%s%f",
  1237.               msg,cnt,(long)xdots*(long)ydots,total_area,
  1238.               cnt/((float)xdots*(float)ydots)*(xxmax-xxmin)*(yymax-yymin));
  1239. #endif
  1240.     stopmsg(4,buf);
  1241. }
  1242.  
  1243. int endswithslash(char *fl)
  1244. {
  1245.    int len;
  1246.    len = strlen(fl);
  1247.    if(len)
  1248.       if(fl[--len] == SLASHC)
  1249.      return(1);
  1250.    return(0);
  1251. }
  1252.  
  1253. /* --------------------------------------------------------------------- */
  1254. static char seps[] = {"' ','\t',\n',\r'"};
  1255. char *get_ifs_token(char *buf,FILE *ifsfile)
  1256. {
  1257.    char *bufptr;
  1258.    for(;;)
  1259.    {
  1260.       if(file_gets(buf,200,ifsfile) < 0)
  1261.          return(NULL);
  1262.       else
  1263.       {
  1264.          if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1265.             *bufptr = 0;
  1266.          if((bufptr = strtok(buf, seps)) != NULL)
  1267.             return(bufptr);
  1268.       }
  1269.    }
  1270. }
  1271.  
  1272. FCODE insufficient_ifs_mem[]={"Insufficient memory for IFS"};
  1273. int numaffine;
  1274. int ifsload()            /* read in IFS parameters */
  1275. {
  1276.    int i;
  1277.    FILE *ifsfile;
  1278.    char buf[201];
  1279.    char *bufptr;
  1280.    int ret,rowsize;
  1281.  
  1282.    if (ifs_defn) { /* release prior parms */
  1283.       farmemfree((char far *)ifs_defn);
  1284.       ifs_defn = NULL;
  1285.       }
  1286.  
  1287.    ifs_type = 0;
  1288.    rowsize = IFSPARM;
  1289.    if (find_file_item(IFSFileName,IFSName,&ifsfile) < 0)
  1290.       return(-1);
  1291.  
  1292.    file_gets(buf,200,ifsfile);
  1293.    if((bufptr = strchr(buf,';')) != NULL) /* use ';' as comment to eol */
  1294.       *bufptr = 0;
  1295.    
  1296.    strlwr(buf);
  1297.    bufptr = &buf[0];
  1298.    while (*bufptr) {
  1299.       if (strncmp(bufptr,"(3d)",4) == 0) {
  1300.      ifs_type = 1;
  1301.      rowsize = IFS3DPARM;
  1302.      }
  1303.       ++bufptr;
  1304.       }
  1305.  
  1306.    for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1307.       ((float *)tstack)[i] = 0;
  1308.    i = ret = 0;
  1309.    bufptr = get_ifs_token(buf,ifsfile);
  1310.    while(bufptr != NULL)
  1311.    {
  1312.       if(sscanf(bufptr," %f ",&((float *)tstack)[i]) != 1)
  1313.          break ;
  1314.       if (++i >= NUMIFS*rowsize) 
  1315.       {
  1316.          static FCODE msg[]={"IFS definition has too many lines"};
  1317.         stopmsg(0,msg);
  1318.         ret = -1;
  1319.         break;
  1320.       }
  1321.       if((bufptr = strtok( NULL, seps ))==NULL)
  1322.       {
  1323.          if((bufptr = get_ifs_token(buf,ifsfile)) == NULL)
  1324.          {
  1325.             ret = -1;
  1326.             break;
  1327.          }   
  1328.       }
  1329.       if(ret == -1)
  1330.          break;
  1331.       if(*bufptr == '}')
  1332.          break;
  1333.    }
  1334.    
  1335.    if ((i % rowsize) != 0 || *bufptr != '}') {
  1336.       static FCODE msg[]={"invalid IFS definition"};
  1337.       stopmsg(0,msg);
  1338.       ret = -1;
  1339.       }
  1340.    if (i == 0 && ret == 0) {
  1341.       static FCODE msg[]={"Empty IFS definition"};
  1342.       stopmsg(0,msg);
  1343.       ret = -1;
  1344.       }
  1345.    fclose(ifsfile);
  1346.  
  1347.    if (ret == 0) {
  1348.       numaffine = i/rowsize;
  1349.       if ((ifs_defn = (float far *)farmemalloc(
  1350.             (long)((NUMIFS+1)*IFS3DPARM*sizeof(float)))) == NULL) {
  1351.      stopmsg(0,insufficient_ifs_mem);
  1352.      ret = -1;
  1353.      }
  1354.       else
  1355.      for (i = 0; i < (NUMIFS+1)*IFS3DPARM; ++i)
  1356.         ifs_defn[i] = ((float *)tstack)[i];
  1357.    }
  1358.    return(ret);
  1359. }
  1360. /* TW 5-31-94 - added search of current directory for entry files if
  1361.    entry item not found */
  1362.  
  1363. int find_file_item(char *filename,char *itemname,FILE **fileptr)
  1364. {
  1365.    FILE *infile=NULL;
  1366.    int found = 0;
  1367.    if((found=find_one_file_item(filename,itemname,&infile)) != 0) 
  1368.    {  /* search for file */
  1369.       int out;
  1370.       char drive[FILE_MAX_DRIVE];
  1371.       char dir[FILE_MAX_DIR];
  1372.       char fname[FILE_MAX_FNAME];
  1373.       char ext[FILE_MAX_EXT];
  1374.       char fullpath[FILE_MAX_PATH];
  1375.       splitpath(filename,drive,dir,fname,ext);
  1376.       makepath(fullpath,drive,dir,"*",ext);
  1377.       out = fr_findfirst(fullpath);
  1378.       found = 0;
  1379.       while(out == 0) 
  1380.       {
  1381.          char msg[200];
  1382.          DTA.filename[FILE_MAX_FNAME+FILE_MAX_EXT-2]=0;
  1383.          sprintf(msg,"Searching %13s for %s      ",DTA.filename,itemname);
  1384.          showtempmsg(msg);
  1385.          if(!(DTA.attribute & SUBDIR) && 
  1386.              strcmp(DTA.filename,".")&&
  1387.              strcmp(DTA.filename,"..")) {    
  1388. #ifndef XFRACT
  1389.             strlwr(DTA.filename);
  1390. #endif
  1391.             splitpath(DTA.filename,NULL,NULL,fname,ext);
  1392.             makepath(fullpath,drive,dir,fname,ext);
  1393.             if((found=find_one_file_item(fullpath,itemname,&infile)) == 0) 
  1394.             {
  1395.                strcpy(filename,fullpath);
  1396.                break;
  1397.             }   
  1398.          }   
  1399.          out = fr_findnext();
  1400.       }
  1401.       cleartempmsg();
  1402.       if(found != 0)
  1403.       {
  1404.          sprintf(fullpath,"'%s' file entry item not found",itemname);
  1405.          stopmsg(0,fullpath);
  1406.          return(-1);
  1407.       }
  1408.    }
  1409.    /* found file */   
  1410.    if(fileptr != NULL)
  1411.       *fileptr = infile;
  1412.    else if(infile != NULL)
  1413.       fclose(infile);   
  1414.    return(0);
  1415. }
  1416.  
  1417. static int find_one_file_item(char *filename,char *itemname,FILE **infile)
  1418. {
  1419.    char fullpathname[FILE_MAX_PATH];
  1420.    char fname[FILE_MAX_FNAME];
  1421.    char ext[FILE_MAX_EXT];
  1422.  
  1423.    splitpath(filename ,NULL,NULL,fname,ext);
  1424.    makepath(fullpathname,""   ,"" ,fname,ext);
  1425.  
  1426.    /* first try current directory */
  1427.    if(checkcurdir == 0 || access(fullpathname,0) != 0)
  1428.       strcpy(fullpathname,filename);   
  1429.    
  1430.    /* now binary node as of 2/95 TW */
  1431.    if ((*infile = fopen(fullpathname,"rb")) == NULL) {
  1432.        return(-1);
  1433.       }
  1434.    /* 
  1435.       Scan_entries() resuses code from gfe_choose_entry() in PROMPTS1.C. The
  1436.       original code used text mode, which made ftell() and fseek() unreliable
  1437.       in cases where files have garbage after the EOF.
  1438.     */
  1439.    if(scan_entries(*infile, NULL, itemname)<0)
  1440.       return(0);
  1441.    fclose(*infile);
  1442.    infile = NULL;
  1443.    return(-1);
  1444. }
  1445.  
  1446. int file_gets(char *buf,int maxlen,FILE *infile)
  1447. {
  1448.    int len,c;
  1449.    /* similar to 'fgets', but file may be in either text or binary mode */
  1450.    /* returns -1 at eof, length of string otherwise */
  1451.    if (feof(infile)) return -1;
  1452.    len = 0;
  1453.    while (len < maxlen) {
  1454.       if ((c = getc(infile)) == EOF || c == '\032') {
  1455.      if (len) break;
  1456.      return -1;
  1457.      }
  1458.       if (c == '\n') break;             /* linefeed is end of line */
  1459.       if (c != '\r') buf[len++] = (char)c;    /* ignore c/r */
  1460.       }
  1461.    buf[len] = 0;
  1462.    return len;
  1463. }
  1464.  
  1465. int first_err = 1;
  1466.  
  1467. #ifndef XFRACT
  1468. #ifdef WINFRACT
  1469. /* call this something else to dodge the QC4WIN bullet... */
  1470. int win_matherr( struct exception *except )
  1471. #else
  1472. int _cdecl matherr( struct exception *except )
  1473. #endif
  1474. {
  1475.     static FCODE msg[]={"Math error, but we'll try to keep going"};
  1476.     if(first_err)
  1477.     {
  1478.        if(debugflag == 4000 || debugflag == 3200)stopmsg(0,msg);
  1479.        first_err = 0;
  1480.     }
  1481.     if(debugflag)
  1482.     {
  1483.        static int ct = 0;
  1484.        static FILE *fp=NULL;
  1485.        if(fp==NULL)
  1486.       fp = fopen("matherr","w");
  1487.        if(ct++ < 100)
  1488.        {
  1489.       fprintf(fp,"err:  %d\nname: %s\narg:  %e\n",
  1490.           except->type, except->name, except->arg1);
  1491.       fflush(fp);
  1492.        }
  1493.     }
  1494.     if( except->type == DOMAIN )
  1495.     {
  1496.     char buf[40];
  1497.     sprintf(buf,"%e",except->arg1);
  1498.     /* This test may be unnecessary - from my experiments if the
  1499.        argument is too large or small the error is TLOSS not DOMAIN */
  1500.     if(strstr(buf,"IN")||strstr(buf,"NAN"))  /* trashed arg? */
  1501.                /* "IND" with MSC, "INF" with BC++ */
  1502.     {
  1503.        if( strcmp( except->name, s_sin ) == 0 )
  1504.        {
  1505.           except->retval = 0.0;
  1506.           return(1);
  1507.        }
  1508.        else if( strcmp( except->name, s_cos ) == 0 )
  1509.        {
  1510.           except->retval = 1.0;
  1511.           return(1);
  1512.        }
  1513.        else if( strcmp( except->name, s_log ) == 0 )
  1514.        {
  1515.           except->retval = 1.0;
  1516.           return(1);
  1517.        }
  1518.        }
  1519.     }
  1520.     if( except->type == TLOSS )
  1521.     {
  1522.        /* try valiantly to keep going */
  1523.        if( strcmp( except->name, s_sin ) == 0 )
  1524.        {
  1525.           except->retval = 0.5;
  1526.           return(1);
  1527.        }
  1528.        else if( strcmp( except->name, s_cos ) == 0 )
  1529.        {
  1530.           except->retval = 0.5;
  1531.           return(1);
  1532.        }
  1533.     }
  1534.     /* shucks, no idea what went wrong, but our motto is "keep going!" */
  1535.     except->retval = 1.0;
  1536.     return(1);
  1537. }
  1538. #endif
  1539.  
  1540. void roundfloatd(double *x) /* make double converted from float look ok */
  1541. {
  1542.    char buf[30];
  1543.    sprintf(buf,"%-10.7g",*x);
  1544.    *x = atof(buf);
  1545. }
  1546.  
  1547. /* fake a keystroke, returns old pending key */
  1548. int ungetakey(int key)
  1549. {
  1550.    int old;
  1551.    old = keybuffer;
  1552.    keybuffer = key;
  1553.    return(old);
  1554. }
  1555.  
  1556. #if _MSC_VER == 800
  1557. #ifdef FIXTAN_DEFINED
  1558. #undef tan
  1559. /* !!!!! stupid MSVC tan(x) bug fix !!!!!!!!            */
  1560. /* tan(x) can return -tan(x) if -pi/2 < x < pi/2       */
  1561. /* if tan(x) has been called before outside this range. */
  1562. double fixtan( double x )
  1563.    {
  1564.    double y;
  1565.  
  1566.    y = tan(x);
  1567.    if ((x > -PI/2 && x < 0 && y > 0) || (x > 0 && x < PI/2 && y < 0))
  1568.       y = -y;
  1569.    return y;
  1570.    }
  1571. #define tan fixtan
  1572. #endif
  1573. #endif
  1574.